#ifndef PROGRAM_H
#define PROGRAM_H

/*
 * A compiled program consists of several data blocks, all allocated
 * contiguously in memory to enhance the working set. During compilation,
 * the blocks will be allocated separately, as the final size is
 * unknown. When compilation is done, the blocks will be copied into
 * the one big area.
 *
 * There are 5 different blocks of information for each program:
 * 1. The program itself. Consists of machine code instructions for a virtual
 *    stack machine. The size of the program must not be bigger than
 *    65535 bytes, as 16 bit pointers are used. Who would ever need a bigger
 *    program :-)
 * 2. Function names. All local functions that has been defined or called,
 *    with the address of the function in the program. Inherited functions
 *    will be found here too, with information of how far up the inherit
 *    chain that the function was defined.
 * 3. String table. All strings used in the program. They are all pointers
 *    into the shared string area. Thus, they are easily found and deallocated
 *    when the object is destructed.
 * 4. Table of variable names. They all point into the shared string table.
 * 5. Line number information. A table which tells at what address every
 *    line belongs to. The table has the same number of entries as the
 *    programs has source lines. This is used at errors, to find out the
 *    line number of the error.  This is usually swapped out to save space.
 *    First entry is the length of the table.
 * 6. List of inherited objects.
 */

/* The semantics of the flags are currently as follows:

   (1) A function is either a definition, a prototype or an undefined
   function

   (2) A definition is an address that executes code when
   it is jumped to and finishes with a return.
   The address is labeled by the following info:
   function name, type, flags,number of arguments, number of locals,
   argument types.

   (3) A prototype does not execute code, and is basically a label with
   the following info:
   argument types (optionally also argument names),function name,
   type, flags, number of arguments

   (4) An undefined function is an unknown function that has been called or
   a label that is as yet not known to be a prototype or definition

   Note that the above rules apply to comments in compiler.c as well.
   In particular, a known prototype is not undefined. When 'function'
   by itself is used, (1) is always meant.

   FUNC_INHERITED - The function entry that exists in this object actually
   is a function in an object we inherited
   FUNC_UNDEFINED - see (4)
   FUNC_STRICT_TYPES - compiled with strict type testing
   FUNC_PROTOTYPE - see (3)
   FUNC_ALIAS     - This entry refers us to another entry, usually because
   this function was overloaded by that function

   Sym
 */
#define FUNC_PROTOTYPE		0x0008
#define FUNC_VARARGS		0x0020

#define LOCAL_MOD_UNUSED	0x0200

#define ADDRESS_TYPE	unsigned int
#define ADDRESS_MAX	UINT_MAX

typedef struct {
	char *name;
	unsigned short type;
	unsigned char num_arg;
	unsigned char num_local;
	unsigned int address;
} function_t;

typedef struct {
	char *name;
	unsigned short type;	/* Type of variable. See above. TYPE_ */
} variable_t;

typedef struct program_s {
	char *name;			/* Name of file that defined prog */
	unsigned short flags;
	unsigned short ref;			/* Reference count */
	unsigned short func_ref;
	char *program;		/* The binary instructions */
	unsigned char *line_info;   /* Line number information */
	unsigned short *file_info;
	int line_swap_index;	/* Where line number info is swapped */
	function_t *function_table;
	unsigned short *function_flags; /* separate for alignment reasons */
	char **strings;		/* All strings uses by the program */
	char **variable_table;	/* variables defined by this program */
	unsigned short *variable_types;	/* variables defined by this program */
	int total_size;		/* Sum of all data in this struct */
	/* TODO: without inheritance, is this still necessary? */
	/*
	 * The types of function arguments are saved where 'argument_types'
	 * points. It can be a variable number of arguments, so allocation is
	 * done dynamically. To know where first argument is found for function
	 * 'n' (number of function), use 'type_start[n]'. These two arrays will
	 * only be allocated if '#pragma save_types' has been specified. This
	 * #pragma should be specified in files that are commonly used for
	 * inheritance. There are several lines of code that depends on the type
	 * length (16 bits) of 'type_start' (sorry !).
	 */
	unsigned short *argument_types;
#define INDEX_START_NONE		65535
	unsigned short *type_start;
	/*
	 * And now some general size information.
	 */
	unsigned short program_size;/* size of this instruction code */
	unsigned short num_functions_defined;
	unsigned short num_strings;
	unsigned short num_variables_total;
	unsigned short num_variables_defined;
} program_t;

extern int total_num_prog_blocks;
extern int total_prog_block_size;

void reference_prog(program_t *, char *);
void free_prog(program_t *, int);
void deallocate_program(program_t *);

#endif
